import os
import re,time
import requests
import threading
from   tkinter import messagebox

def get_source_version(kernel:requests.Response=None) -> str|None:
    try   :return re.findall('version = \'(.*?)\'', kernel.text if kernel else get_kernel().text)[0]
    except:return None

def get_current_version() -> str|None:
    try   :return re.findall('version = \'(.*?)\'', open('./lib/main/kernel.py', 'r', encoding='utf-8').read())[0]
    except:return None

def get_kernel() -> requests.Response|None:
    try   :return requests.get('https://gitee.com/LinmengenData/open-bilibili-downloader/raw/master/main.py', timeout=(3, 5))
    except:return None

def compare_version(kernel:requests.Response=None) -> bool:
    source_version  = get_source_version(kernel)
    current_version = get_current_version()
    if source_version is None or current_version is None:return False
    if 'V' not in source_version or 'V' not in current_version:return False
    return source_version != current_version
    
def write_kernel(content:requests.Response.content) -> bool:
    try:
        os.makedirs('./lib/main', exist_ok=True)
        with open('./lib/main/kernel.py', 'wb') as kernel_stream:
            kernel_stream.write(content)
    except:return False
    return True

def show_error_dialog(error_message:str) -> None:
    threading.Thread(target=lambda:messagebox.showerror('错误', error_message)).start()

def show_error_dialog_into_titletext(error_message:str) -> None:
    def show_error_dialog_into_titletext_thread():
        wait_for_program_init()
        main.kernel.app.root.title("Open Bilibili Downloader {} ({})".format(get_current_version(), error_message))
    threading.Thread(target=show_error_dialog_into_titletext_thread).start()

def wait_for_program_init() -> None:
    while MainProgramIsRunning:
        try   :main.kernel.app.root
        except:time.sleep(0.1)
        else  :break

def hot_update() -> None:
    while MainProgramIsRunning:
        try:
            kernel = get_kernel()
            if  compare_version(kernel):
                current_vision = get_current_version()
                if not write_kernel(kernel.content):
                    wait_for_program_init()
                    main.kernel.app.root.title("Open Bilibili Downloader {} (新版本 {} 更新失败，请以管理员权限重新打开程序)".format(current_vision, get_source_version(kernel)))
                else:
                    wait_for_program_init()
                    main.kernel.app.root.title("Open Bilibili Downloader {} (新版本 {} 已完成下载，请重启软件以完成更新)".format(current_vision, get_source_version(kernel)))
                    current_vision = get_current_version()
        except:time.sleep(5)
        for _ in range(10):
            time.sleep(0.5)
            if not MainProgramIsRunning:break

if __name__ == '__main__':
    MainProgramIsRunning = True
    try:
        threading.Thread(target=hot_update).start()
        try:
            import main.kernel
            main.kernel.main()
        except:
            try:
                kernel = get_kernel()
                if not write_kernel(kernel.content):
                    show_error_dialog('内核已损坏且暂时无法恢复，请以管理员权限打开程序以再次尝试，或者重新安装程序')
                else:
                    try:
                        import main.kernel
                        main.kernel.main()
                    except:show_error_dialog('内核已损坏且暂时无法恢复，请以管理员权限打开程序以再次尝试，或者重新安装程序')
            except:show_error_dialog('内核已损坏且暂时无法恢复，请检查网络连接并重新打开程序，或者重新安装程序')
    except Exception as Error:show_error_dialog('未知错误：' + Error)
    MainProgramIsRunning = False